HAL SAI typical use cases for migration

This section provides information about the HAL SAI Typical use cases for migration.

The processes for transmitting and receiving data using polling, interrupt, or DMA remain unchanged in HAL1 and HAL2.

However, the configuration has been limited to the minimum required parameters within the HAL_SAI_SetConfig() function. For additional optional parameters, which are only needed in specific use cases, are handled through dedicated configuration functions that can be used when needed, such as HAL_SAI_SetSync() etc.

In the following use cases, the hardware instances used are:

  • SAI1_A configured as slave receiver (RX)

  • SAI1_B configured as master transmitter (TX)

Use case: HAL SAI Transmit/Receive in polling mode

HAL1

HAL2

SAI Transmit/Receive in polling mode

   @startuml
   participant "User Application" as p1
   participant "HAL SAI driver" as p2

   alt polling
   p1->p2: HAL_SAI_Init(&hSAI1_B)
   p1->p2: HAL_SAI_Transmit(&hSAI1_B,\n                                pTxData,\n                                BUFFER_SIZE,\n                                1000)
   note over p2 #00FF00
   Transmitting data ongoing
   end note
   p2-->p1: <color #Green> HAL_OK
   else
   p1->p2: HAL_SAI_Init(&hSAI1_A)
   p1->p2: HAL_SAI_Receive(&hSAI1_A,\n                                pRxData,\n                                BUFFER_SIZE,\n                                1000)
   note over p2 #00FF00
   Receiving data ongoing
   end note
   p2-->p1: <color #Green> HAL_OK

   @enduml

SAI Transmit/Receive in polling mode

   @startuml
   participant "User Application" as p1
   participant "HAL SAI driver" as p2

   alt polling
   p1->p2: HAL_SAI_Init(&hSAI1_B)
   p1->p2: HAL_SAI_SetConfig(&hSAI1_B, &sai_config)
   p1->p2: HAL_SAI_Transmit(&hSAI1_B,\n                                pTxData,\n                                BUFFER_SIZE,\n                                1000)
   note over p2 #00FF00
   Transmitting data ongoing
   end note
   p2-->p1: <color #Green> HAL_OK
   else
   p1->p2: HAL_SAI_Init(&hSAI1_A)
   p1->p2: HAL_SAI_SetConfig(&hSAI1_A, &sai_config)
   p1->p2: HAL_SAI_Receive(&hSAI1_A,\n                                pRxData,\n                                BUFFER_SIZE,\n                                1000)
   note over p2 #00FF00
   Receiving data ongoing
   end note
   p2-->p1: <color #Green> HAL_OK

   @enduml

Code snippet

HAL1

HAL2

#define BUFFER_SIZE 20
uint8_t   pTxData[BUFFER_SIZE] = { 1,  2,  3,  4,  5,  6,  7,  8,  9, 10, \
                  11, 12, 13, 14, 15, 16, 17, 18, 19, 20};
uint8_t   pRxData[BUFFER_SIZE];
SAI_HandleTypeDef hSAI1_A, hSAI1_B;



PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_SAI1;
PeriphClkInit.Sai1ClockSelection = RCC_SAI1CLKSOURCE_PLL1;
HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit);
__HAL_RCC_SAI1_CLK_ENABLE()

hSAI1_A.Instance = SAI1_Block_A;
hSAI1_A.Init.AudioMode = SAI_MODESLAVE_RX;
hSAI1_A.Init.AudioFrequency = SAI_AUDIO_FREQUENCY_MCKDIV;
hSAI1_A.Init.NoDivider = SAI_MASTERDIVIDER_ENABLE;
hSAI1_A.Init.MckOverSampling = SAI_MCK_OVERSAMPLING_DISABLE;
hSAI1_A.Init.Protocol = SAI_FREE_PROTOCOL;
hSAI1_A.Init.DataSize = SAI_DATASIZE_8;
hSAI1_A.Init.FirstBit = SAI_FIRSTBIT_MSB;
hSAI1_A.Init.ClockStrobing = SAI_CLOCKSTROBING_RISINGEDGE;
hSAI1_A.FrameInit.FrameLength = 16;
hSAI1_A.FrameInit.ActiveFrameLength = 8;
hSAI1_A.FrameInit.FSDefinition = SAI_FS_STARTFRAME;
hSAI1_A.FrameInit.FSPolarity = SAI_FS_ACTIVE_LOW;
hSAI1_A.FrameInit.FSOffset = SAI_FS_FIRSTBIT;
hSAI1_A.SlotInit.FirstBitOffset = 0;
hSAI1_A.SlotInit.SlotSize = SAI_SLOTSIZE_DATASIZE;
hSAI1_A.SlotInit.SlotNumber = 1;
hSAI1_A.SlotInit.SlotActive = 0x00000001;

hSAI1_A.Init.Synchro = SAI_SYNCHRONOUS;
hSAI1_A.Init.SynchroExt = SAI_SYNCEXT_OUTBLOCKA_ENABLE;
hSAI1_A.Init.CompandingMode = SAI_NOCOMPANDING;
hSAI1_A.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_FULL;
hSAI1_A.Init.MckOutput = SAI_MCK_OUTPUT_ENABLE;
hSAI1_A.Init.OutputDrive = SAI_OUTPUTDRIVE_DISABLE;
hSAI1_A.Init.TriState = SAI_OUTPUT_NOTRELEASED;
hSAI1_A.Init.MonoStereoMode = SAI_STEREOMODE;
hSAI1_A.Init.PdmInit.Activation = DISABLE;
hSAI1_A.Init.PdmInit.MicPairsNbr = 1;
hSAI1_A.Init.PdmInit.ClockEnable = SAI_PDM_CLOCK1_ENABLE;



HAL_SAI_Init(&hSAI1_A);

/* Ensure that all GPIOs of SAI1_A are
   configured properly
*/

hSAI1_B.Instance = SAI1_Block_B;
hSAI1_B.Init.AudioMode = SAI_MODEMASTER_TX;
hSAI1_B.Init.AudioFrequency = SAI_AUDIO_FREQUENCY_MCKDIV;
hSAI1_B.Init.NoDivider = SAI_MASTERDIVIDER_ENABLE;
hSAI1_B.Init.MckOverSampling = SAI_MCK_OVERSAMPLING_DISABLE;
hSAI1_B.Init.Protocol = SAI_FREE_PROTOCOL;
hSAI1_B.Init.DataSize = SAI_DATASIZE_8;
hSAI1_B.Init.FirstBit = SAI_FIRSTBIT_MSB;
hSAI1_B.Init.ClockStrobing = SAI_CLOCKSTROBING_FALLINGEDGE;
hSAI1_B.FrameInit.FrameLength = 16;
hSAI1_B.FrameInit.ActiveFrameLength = 8;
hSAI1_B.FrameInit.FSDefinition = SAI_FS_STARTFRAME;
hSAI1_B.FrameInit.FSPolarity = SAI_FS_ACTIVE_LOW;
hSAI1_B.FrameInit.FSOffset = SAI_FS_FIRSTBIT;
hSAI1_B.SlotInit.FirstBitOffset = 0;
hSAI1_B.SlotInit.SlotSize = SAI_SLOTSIZE_DATASIZE;
hSAI1_B.SlotInit.SlotNumber = 1;
hSAI1_B.SlotInit.SlotActive = 0x00000001;

hSAI1_B.Init.Synchro = SAI_ASYNCHRONOUS;
hSAI1_B.Init.SynchroExt = SAI_SYNCEXT_OUTBLOCKB_ENABLE;
hSAI1_B.Init.CompandingMode = SAI_NOCOMPANDING;
hSAI1_B.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_FULL;
hSAI1_B.Init.MckOutput = SAI_MCK_OUTPUT_DISABLE;
hSAI1_B.Init.OutputDrive = SAI_OUTPUTDRIVE_DISABLE;
hSAI1_B.Init.TriState = SAI_OUTPUT_NOTRELEASED;
hSAI1_B.Init.MonoStereoMode = SAI_STEREOMODE;
hSAI1_B.Init.PdmInit.Activation = DISABLE;
hSAI1_B.Init.PdmInit.MicPairsNbr = 1;
hSAI1_B.Init.PdmInit.ClockEnable = SAI_PDM_CLOCK1_ENABLE;



HAL_SAI_Init(&hSAI1_B);

/* Ensure that all GPIOs of SAI1_B are
   configured properly
*/

HAL_SAI_Transmit(&hSAI1_B, pTxData,
                 BUFFER_SIZE, 1000);

HAL_SAI_Receive(&hSAI1_A, pRxData,
                BUFFER_SIZE, 1000);
#define BUFFER_SIZE 20
uint8_t   pTxData[BUFFER_SIZE] = { 1,  2,  3,  4,  5,  6,  7,  8,  9, 10, \
                  11, 12, 13, 14, 15, 16, 17, 18, 19, 20};
uint8_t   pRxData[BUFFER_SIZE];
hal_sai_handle_t hSAI1_A, hSAI1_B;
hal_sai_config_t sai_configA,sai_configB;
hal_sai_pdm_mic_delay_t pdm_mic_delay;

HAL_RCC_SAI1_SetKernelClkSource(HAL_RCC_SAI1_CLK_SRC_PLL1R);
HAL_RCC_SAI1_EnableClock();

HAL_SAI_Init(&hSAI1_A, HAL_SAI1_A);
sai_configA.protocol            = HAL_SAI_PROTOCOL_FREE;
sai_configA.mode                = HAL_SAI_MODE_SLAVE_RX;
sai_configA.data_size           = HAL_SAI_DATA_SIZE_8BITS;
sai_configA.bit_order           = HAL_SAI_BIT_ORDER_MSB;
sai_configA.clock_strobing_edge = HAL_SAI_CLOCK_STROBING_RISING_EDGE;
sai_configA.audio_frequency     = HAL_SAI_AUDIO_FREQUENCY_8KHZ;
sai_configA.mclk_oversampling   = HAL_SAI_MCLK_OVERSAMPLING_DISABLE;
sai_configA.frame.frame_length        = 16;
sai_configA.frame.active_frame_length = 8;
sai_configA.frame.fs_definition       = HAL_SAI_FS_START_FRAME;
sai_configA.frame.fs_polarity         = HAL_SAI_FS_POLARITY_FALLING;
sai_configA.frame.fs_offset           = HAL_SAI_FS_FIRST_BIT;
sai_configA.slot.slot_first_bit_offset = 0;
sai_configA.slot.slot_size             = HAL_SAI_SLOT_SIZE_DATA_SIZE;
sai_configA.slot.slot_number           = 1;
sai_configA.slot.slot_active           = HAL_SAI_SLOT_ACTIVE_0;
HAL_SAI_SetConfig(&hSAI1_A, &sai_configA);



/* Additional optional configuration
   feature when needed
*/
HAL_SAI_SetSync(&hSAI1_A, HAL_SAI_SYNC_INTERNAL);












/* Ensure that all GPIOs of SAI1_A are
   configured properly
*/

HAL_SAI_Init(&hSAI1_B, HAL_SAI1_B);
sai_configB.protocol            = HAL_SAI_PROTOCOL_FREE;
sai_configB.mode                = HAL_SAI_MODE_MASTER_TX;
sai_configB.data_size           = HAL_SAI_DATA_SIZE_8BITS;
sai_configB.bit_order           = HAL_SAI_BIT_ORDER_MSB;
sai_configB.clock_strobing_edge = HAL_SAI_CLOCK_STROBING_FALLING_EDGE;
sai_configB.audio_frequency     = HAL_SAI_AUDIO_FREQUENCY_8KHZ;
sai_configB.mclk_oversampling   = HAL_SAI_MCLK_OVERSAMPLING_DISABLE;
sai_configB.frame.frame_length        = 16;
sai_configB.frame.active_frame_length = 8;
sai_configB.frame.fs_definition       = HAL_SAI_FS_START_FRAME;
sai_configB.frame.fs_polarity         = HAL_SAI_FS_POLARITY_FALLING;
sai_configB.frame.fs_offset           = HAL_SAI_FS_FIRST_BIT;
sai_configB.slot.slot_first_bit_offset = 0;
sai_configB.slot.slot_size             = HAL_SAI_SLOT_SIZE_DATA_SIZE;
sai_configB.slot.slot_number           = 1;
sai_configB.slot.slot_active           = HAL_SAI_SLOT_ACTIVE_0;
HAL_SAI_SetConfig(&hSAI1_B, &sai_configB);

/* Additional optional configuration
   feature when needed
*/
HAL_SAI_SetSync(&hSAI1_B, HAL_SAI_SYNC_NO);












/* Ensure that all GPIOs of SAI1_B are
   configured properly
*/

HAL_SAI_Transmit(&hSAI1_B, pTxData,
                 BUFFER_SIZE, 1000);

HAL_SAI_Receive(&hSAI1_A, pRxData,
                BUFFER_SIZE, 1000);

Use case: HAL SAI Transmit/Receive IT

SAI HAL Transmit/Receive IT

   @startuml
   participant "User Application" as p1
   participant "HAL SAI driver" as p2
   participant "SAI1_IRQHandler" as p3

   alt Transmit IT
       p1->p2: HAL_SAI_Transmit_IT(&hSAI1_B,\n                                    pTxData,\n                                    BUFFER_SIZE)
       note over p2 #00FF00
       Transmitting data ongoing
       end note

       p3<-: SAI1_B data interrupt
       p3->p2: HAL_SAI_IRQHandler(&hSAI1_B)
       note over p2 #FFFF99
       All data (size_byte == hSAI1_B->tx_xfer_count) have been transmitted
       end note
       note over p2 #00FF00
       End of transmitting data
       end note
       p2->p1: HAL_SAI_TxCpltCallback(&hSAI1_B)
   else Receive IT
       p1->p2: HAL_SAI_Receive_IT(&hSAI1_A,\n                                    pRxData,\n                                    BUFFER_SIZE)
       note over p2 #00FF00
       Receiving data ongoing
       end note

       p3<-: SAI1_A data interrupt
       p3->p2: HAL_SAI_IRQHandler(&hSAI1_A)
       note over p2 #FFFF99
       All data (size_byte == hSAI1_A->rx_xfer_count) have been received
       end note
       note over p2 #00FF00
       End of receiving data
       end note
       p2->p1: HAL_SAI_RxCpltCallback(&hSAI1_A)

   end
   @enduml

Code snippet

HAL1

HAL2

#define BUFFER_SIZE 20
uint8_t   pTxData[BUFFER_SIZE] = { 1,  2,  3,  4,  5,  6,  7,  8,  9, 10, \
                  11, 12, 13, 14, 15, 16, 17, 18, 19, 20};
uint8_t   pRxData[BUFFER_SIZE];
SAI_HandleTypeDef hSAI1_A, hSAI1_B;

/* Ensure that all required peripherals
  (SAI1_A, SAI1_B, GPIO, NVIC interrupts, etc..) are configured properly
*/




/* Start a SAI Transmit in interruption mode */
HAL_SAI_Transmit_IT(&hSAI1_B, pTxData,
                    BUFFER_SIZE);





/* Start a SAI Receive in interruption mode */
HAL_SAI_Receive_IT(&hSAI1_A, pRxData,
                   BUFFER_SIZE);



/* Ensure that HAL_SAI_IRQHandler() is called for the required instance
   within the corresponding ISR handlers according to the product.
*/
#define BUFFER_SIZE 20
uint8_t   pTxData[BUFFER_SIZE] = { 1,  2,  3,  4,  5,  6,  7,  8,  9, 10, \
                  11, 12, 13, 14, 15, 16, 17, 18, 19, 20};
uint8_t   pRxData[BUFFER_SIZE];
hal_sai_handle_t hSAI1_A, hSAI1_B;

/* Ensure that all required peripherals
  (SAI1_A, SAI1_B, GPIO, NVIC interrupts, etc..) are configured properly
*/



/* Start a SAI Transmit in interruption mode */
HAL_SAI_Transmit_IT(&hSAI1_B, pTxData,
                    BUFFER_SIZE);





/* Start a SAI Receive in interruption mode */
HAL_SAI_Receive_IT(&hSAI1_A, pRxData,
                   BUFFER_SIZE);



/* Ensure that HAL_SAI_IRQHandler() is called for the required instance
   within the corresponding ISR handlers according to the product.
*/

Use case: HAL SAI Receive DMA

Sequence diagram

SAI HAL Receive DMA in circular mode

   @startuml
   participant "User Application" as p1
   participant "<font color=green><b>HAL SAI</b></font>" as p2
   participant "DMA" as p3
   participant "DMAx_IRQHandler" as p4

   p1->p2: HAL_SAI_Receive_DMA(&hSAI1_A,\n                                    pRxData,\n                                    BUFFER_SIZE);
   p2->p3: HAL_DMA_Start_IT()
   p4<-: DMAx half complete interrupt
   p4->p3: HAL_DMA_IRQHandler(&handle_GPDMA1_Channel0)
   p3->p2: XferHalfCpltCallback
   p2->p1: HAL_SAI_RxHalfCpltCallback(&hSAI1_A)
   note over p1 #00FF00
   Half of the data has been received
   end note
   p4<-: DMAx complete interrupt
   p4->p3: HAL_DMA_IRQHandler(&handle_GPDMA1_Channel0)
   p3->p2: XferCpltCallback
   p2->p1: HAL_SAI_RxCpltCallback(&hSAI1_A)
   note over p1 #00FF00
   All data have been received
   end note
   p1->p2: HAL_SAI_DMAStop(&hSAI1_A)

   @enduml

Code snippet

HAL1

HAL2

#define BUFFER_SIZE 20
uint8_t   pRxData[BUFFER_SIZE];
SAI_HandleTypeDef hSAI1_A;
DMA_HandleTypeDef handle_GPDMA1_Channel0;
DMA_NodeConfTypeDef NodeConfig;
DMA_NodeTypeDef Node_GPDMA1_Channel0;
DMA_QListTypeDef List_GPDMA1_Channel0;

/* Ensure that all required peripherals
  (SAI1_A, GPIO etc.) are configured properly */


__HAL_RCC_GPDMA1_CLK_ENABLE();

NodeConfig.NodeType = DMA_GPDMA_LINEAR_NODE;
NodeConfig.Init.Request = GPDMA1_REQUEST_SAI1_A;
NodeConfig.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;
NodeConfig.Init.Direction = DMA_PERIPH_TO_MEMORY;
NodeConfig.Init.SrcInc = DMA_SINC_FIXED;
NodeConfig.Init.DestInc = DMA_DINC_FIXED;
NodeConfig.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_BYTE;
NodeConfig.Init.DestDataWidth = DMA_DEST_DATAWIDTH_BYTE;
NodeConfig.Init.SrcBurstLength = 1;
NodeConfig.Init.DestBurstLength = 1;
NodeConfig.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0|DMA_DEST_ALLOCATED_PORT0;
NodeConfig.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
NodeConfig.Init.Mode = DMA_NORMAL;
NodeConfig.TriggerConfig.TriggerPolarity = DMA_TRIG_POLARITY_MASKED;
NodeConfig.DataHandlingConfig.DataExchange = DMA_EXCHANGE_NONE;
NodeConfig.DataHandlingConfig.DataAlignment = DMA_DATA_RIGHTALIGN_ZEROPADDED;

HAL_DMAEx_List_BuildNode(&NodeConfig, &Node_GPDMA1_Channel0);

HAL_DMAEx_List_InsertNode(&List_GPDMA1_Channel0,
                          NULL, &Node_GPDMA1_Channel0);

HAL_DMAEx_List_SetCircularMode(&List_GPDMA1_Channel0);

handle_GPDMA1_Channel0.Instance = GPDMA1_Channel0;
handle_GPDMA1_Channel0.InitLinkedList.Priority = DMA_LOW_PRIORITY_LOW_WEIGHT;
handle_GPDMA1_Channel0.InitLinkedList.LinkStepMode = DMA_LSM_FULL_EXECUTION;
handle_GPDMA1_Channel0.InitLinkedList.LinkAllocatedPort = DMA_LINK_ALLOCATED_PORT0;
handle_GPDMA1_Channel0.InitLinkedList.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
handle_GPDMA1_Channel0.InitLinkedList.LinkedListMode = DMA_LINKEDLIST_CIRCULAR;

HAL_DMAEx_List_Init(&handle_GPDMA1_Channel0);

HAL_DMAEx_List_LinkQ(&handle_GPDMA1_Channel0, &List_GPDMA1_Channel0);

__HAL_LINKDMA(hSAI1_A,
              hdmarx, handle_GPDMA1_Channel0);


/* Start a SAI Receive in interruption mode */
HAL_SAI_Receive_DMA(&hSAI1_A, pRxData,
                    BUFFER_SIZE);

/* Stop Tx transfer */
HAL_SAI_DMAStop(&hSAI1_A);



/* Check the exact name of the DMA
   IRQ handler from startup file */
#define BUFFER_SIZE 20
uint8_t pRxData[BUFFER_SIZE];
hal_sai_handle_t hSAI1_A;
hal_dma_handle_t hGPDMA1_CH0;
hal_dma_node_t DMA_Node_SAI1_A;


/* Ensure that all required peripherals
  (SAI1_A, GPIO, NVIC etc.) are configured properly */


 HAL_RCC_GPDMA1_EnableClock();

 HAL_DMA_Init(&hGPDMA1_CH0, HAL_GPDMA1_CH0);

 hal_dma_direct_xfer_config_t xfer_cfg_sai1_a_dma;
 xfer_cfg_sai1_a_dma.request         = HAL_GPDMA1_REQUEST_SAI1_A;
 xfer_cfg_sai1_a_dma.direction       = HAL_DMA_DIRECTION_PERIPH_TO_MEMORY;
 xfer_cfg_sai1_a_dma.src_inc         = HAL_DMA_SRC_ADDR_FIXED;
 xfer_cfg_sai1_a_dma.dest_inc        = HAL_DMA_DEST_ADDR_INCREMENTED;
 xfer_cfg_sai1_a_dma.src_data_width  = HAL_DMA_SRC_DATA_WIDTH_BYTE;
 xfer_cfg_sai1_a_dma.dest_data_width = HAL_DMA_DEST_DATA_WIDTH_BYTE;
 xfer_cfg_sai1_a_dma.priority        = HAL_DMA_PRIORITY_LOW_WEIGHT_LOW;

 HAL_DMA_SetConfigPeriphLinkedListCircularXfer(&hGPDMA1_CH0,
                                               &DMA_Node_SAI1_A, &xfer_cfg_sai1_a_dma);

 HAL_DMA_SetLinkedListXferFetchNodePort(&hGPDMA1_CH0, HAL_DMA_PORT0);

 /* Link the Receiver DMA handle to the SAI handle */
 HAL_SAI_SetRxDMA(&hSAI1_A, &hGPDMA1_CH0);





















 /* Start a SAI Receive in interruption mode */
 HAL_SAI_Receive_DMA(&hSAI1_A, pRxData,
                     BUFFER_SIZE);

 /* Stop Tx transfer */
 HAL_SAI_Abort(&hSAI1_A);



/* Check the exact name of the DMA
   IRQ handler from startup file */

Use case: HAL SAI Transmit DMA with Pause/Resume

Sequence diagram

SAI HAL Transmit DMA in circular mode with Pause/Resume

   @startuml
   participant "User Application" as p1
   participant "<font color=green><b>HAL SAI</b></font>" as p2
   participant "DMA" as p3
   participant "DMAx_IRQHandler" as p4

   p1->p2: HAL_SAI_Transmit_DMA(&hSAI1_B,\n                                     pTxData,\n                                    BUFFER_SIZE);
   p2->p3: HAL_DMA_Start_IT()

   p4<-: DMAx half complete interrupt
   p4->p3: HAL_DMA_IRQHandler(&handle_GPDMA1_Channel1)
   p3->p2: XferHalfCpltCallback()
   p2->p1: HAL_SAI_TxHalfCpltCallback(&hSAI1_B)
   note over p1: Half of the data has been transmitted

   alt Pause/Resume DMA
   p1->p2: HAL_SAI_DMAPause(&hSAI1_B)
   p2-->p1: HAL_OK
   note over p1 : Data are no more sent
   p1->p2: HAL_SAI_DMAResume(&hSAI1_B)
   p2-->p1: HAL_OK
   note over p1 : Data transmission resumes
   end

   p4<-: DMAx complete interrupt
   p4->p3: HAL_DMA_IRQHandler(&handle_GPDMA1_Channel1)
   p3->p2: XferCpltCallback()
   p2->p1: HAL_SAI_TxCpltCallback(&hSAI1_B)
   note over p1: All data have been transmitted
   p1->p2: HAL_SAI_DMAStop(&hSAI1_B)

   @enduml

Code snippet

HAL1

HAL2

#define BUFFER_SIZE 20
uint8_t   pTxData[BUFFER_SIZE] = { 1,  2,  3,  4,  5,  6,  7,  8,  9, 10, \
                  11, 12, 13, 14, 15, 16, 17, 18, 19, 20};
SAI_HandleTypeDef hSAI1_B;
DMA_HandleTypeDef handle_GPDMA1_Channel1;
DMA_NodeConfTypeDef NodeConfig;
DMA_NodeTypeDef Node_GPDMA1_Channel1;
DMA_QListTypeDef List_GPDMA1_Channel1;
/* Ensure that all required peripherals
  (SAI1_B, GPIO etc.) are configured properly */


__HAL_RCC_GPDMA1_CLK_ENABLE();

NodeConfig.NodeType = DMA_GPDMA_LINEAR_NODE;
NodeConfig.Init.Request = GPDMA1_REQUEST_SAI1_B;
NodeConfig.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;
NodeConfig.Init.Direction = DMA_MEMORY_TO_PERIPH;
NodeConfig.Init.SrcInc = DMA_SINC_FIXED;
NodeConfig.Init.DestInc = DMA_DINC_FIXED;
NodeConfig.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_BYTE;
NodeConfig.Init.DestDataWidth = DMA_DEST_DATAWIDTH_BYTE;
NodeConfig.Init.SrcBurstLength = 1;
NodeConfig.Init.DestBurstLength = 1;
NodeConfig.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0|DMA_DEST_ALLOCATED_PORT0;
NodeConfig.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
NodeConfig.Init.Mode = DMA_NORMAL;
NodeConfig.TriggerConfig.TriggerPolarity = DMA_TRIG_POLARITY_MASKED;
NodeConfig.DataHandlingConfig.DataExchange = DMA_EXCHANGE_NONE;
NodeConfig.DataHandlingConfig.DataAlignment = DMA_DATA_RIGHTALIGN_ZEROPADDED;
HAL_DMAEx_List_BuildNode(&NodeConfig, &Node_GPDMA1_Channel1);

HAL_DMAEx_List_InsertNode(&List_GPDMA1_Channel1,
                          NULL, &Node_GPDMA1_Channel1);

HAL_DMAEx_List_SetCircularMode(&List_GPDMA1_Channel1);

handle_GPDMA1_Channel1.Instance = GPDMA1_Channel1;
handle_GPDMA1_Channel1.InitLinkedList.Priority = DMA_LOW_PRIORITY_LOW_WEIGHT;
handle_GPDMA1_Channel1.InitLinkedList.LinkStepMode = DMA_LSM_FULL_EXECUTION;
handle_GPDMA1_Channel1.InitLinkedList.LinkAllocatedPort = DMA_LINK_ALLOCATED_PORT1;
handle_GPDMA1_Channel1.InitLinkedList.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
handle_GPDMA1_Channel1.InitLinkedList.LinkedListMode = DMA_LINKEDLIST_CIRCULAR;

HAL_DMAEx_List_Init(&handle_GPDMA1_Channel1);

HAL_DMAEx_List_LinkQ(&handle_GPDMA1_Channel1, &List_GPDMA1_Channel1);

__HAL_LINKDMA(&hSAI1_B,
              hdmatx, handle_GPDMA1_Channel1);


/* Start a SAI Transmit in interruption mode */
HAL_SAI_Transmit_DMA(&hSAI1_B, pTxData,
                     BUFFER_SIZE);

/* Pause DMA */
HAL_SAI_DMAPause(&hSAI1_B);

/* Resume DMA */
HAL_SAI_DMAResume(&hSAI1_B);


/* Stop Tx transfer */
HAL_SAI_DMAStop(&hSAI1_B);

/* Check the exact name of the DMA
   IRQ handler from startup file */
#define BUFFER_SIZE 20
uint8_t   pTxData[BUFFER_SIZE] = { 1,  2,  3,  4,  5,  6,  7,  8,  9, 10, \
                  11, 12, 13, 14, 15, 16, 17, 18, 19, 20};
hal_sai_handle_t hSAI1_B;
hal_dma_node_t DMA_Node_SAI1_B;
hal_dma_handle_t hGPDMA1_CH1;


/* Ensure that all required peripherals
  (SAI1_B, GPIO, NVIC etc.) are configured properly */


/* Configure the DMA TX */

HAL_RCC_GPDMA1_EnableClock();

HAL_DMA_Init(&hGPDMA1_CH1, HAL_GPDMA1_CH1);

hal_dma_direct_xfer_config_t xfer_cfg_sai1_b_dma;
xfer_cfg_sai1_b_dma.request         = HAL_GPDMA1_REQUEST_SAI1_B;
xfer_cfg_sai1_b_dma.direction       = HAL_DMA_DIRECTION_MEMORY_TO_PERIPH;
xfer_cfg_sai1_b_dma.src_inc         = HAL_DMA_SRC_ADDR_INCREMENTED;
xfer_cfg_sai1_b_dma.dest_inc        = HAL_DMA_DEST_ADDR_FIXED;
xfer_cfg_sai1_b_dma.src_data_width  = HAL_DMA_SRC_DATA_WIDTH_BYTE;
xfer_cfg_sai1_b_dma.dest_data_width = HAL_DMA_DEST_DATA_WIDTH_BYTE;
xfer_cfg_sai1_b_dma.priority        = HAL_DMA_PRIORITY_LOW_WEIGHT_LOW;

HAL_DMA_SetConfigPeriphLinkedListCircularXfer(&hGPDMA1_CH1,
                                              &DMA_Node_SAI1_B, &xfer_cfg_sai1_b_dma);

HAL_DMA_SetLinkedListXferFetchNodePort(&hGPDMA1_CH1, HAL_DMA_PORT1);

/* Link the Transmit DMA handle to the SAI handle */
HAL_SAI_SetTxDMA(&hSAI1_B, &hGPDMA1_CH1);


















/* Start a SAI Transmit in interruption mode */
HAL_SAI_Transmit_DMA(&hSAI1_B, pTxData,
                     BUFFER_SIZE);

/* Pause DMA */
HAL_SAI_Pause_DMA(&hSAI1_B);

/* Resume DMA */
HAL_SAI_Resume_DMA(&hSAI1_B);

/* Stop Tx transfer */
HAL_SAI_Abort(&hSAI1_B);


/* Check the exact name of the DMA
   IRQ handler from startup file */

Use case: HAL SAI Mute Tx

Sequence diagram

SAI HAL Transmit Mute

   @startuml
   participant "User Application" as p1
   participant "<font color=green><b>HAL SAI</b></font>" as p2

   p1->p2:HAL_SAI_Transmit_DMA(&hSAI1_B,\n                                     pTxData,\n                                    BUFFER_SIZE)

   note over p1 : Transmission started.
   p1->p2: HAL_SAI_EnableTxMuteMode(&hSAI1_B,\n                                             SAI_ZERO_VALUE)
   note over p1 : The user can choose to send zeroes on muted slots\nor the previously transmitted value depending on mode.
   p1->p2:HAL_SAI_DisableTxMuteMode(&hSAI1_B)

   @enduml

Code snippet

HAL1

HAL2

#define BUFFER_SIZE 20
uint8_t   pTxData[BUFFER_SIZE] = { 1,  2,  3,  4,  5,  6,  7,  8,  9, 10, \
                  11, 12, 13, 14, 15, 16, 17, 18, 19, 20};
SAI_HandleTypeDef hSAI1_B;

/* Ensure that all required peripherals
  (SAI1_B, GPIO, DMA etc.) are configured properly */

/* Mute Tx */
HAL_SAI_Transmit_DMA(&hSAI1_B,
                     pTxData, BUFFER_SIZE);

/* Enable Tx mute with value as 0 */
HAL_SAI_EnableTxMuteMode(&hSAI1_B, SAI_ZERO_VALUE);

/* Disable Tx mute */
HAL_SAI_DisableTxMuteMode(&hSAI1_B);
#define BUFFER_SIZE 20
uint8_t   pTxData[BUFFER_SIZE] = { 1,  2,  3,  4,  5,  6,  7,  8,  9, 10, \
                  11, 12, 13, 14, 15, 16, 17, 18, 19, 20};
hal_sai_handle_t hSAI1_B;

/* Ensure that all required peripherals
  (SAI1_B, GPIO, DMA etc.) are configured properly */

/* Mute Tx */
HAL_SAI_Transmit_DMA(&hSAI1_B,
                     pTxData, BUFFER_SIZE);

/* Enable Tx mute with value as 0 */
HAL_SAI_MuteTx(&hSAI1_B, HAL_SAI_MUTE_MODE_ZERO_VALUE);

/* Disable Tx mute */
HAL_SAI_UnmuteTx(&hSAI1_B);